package mapEditor;

import context.*;

import interactor.DrawEllipseInteractor;
import interactor.DrawLineInteractor;
import interactor.DrawParallelogramInteractor;
import interactor.DrawPathInteractor;
import interactor.DrawPolygonInteractor;
import interactor.DrawTextInteractor;
import interactor.EditInteractor;
import interactor.Interactor;
import interactor.MeasureInteractor;

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Dimension;
import java.awt.geom.AffineTransform;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;

import javax.swing.JPanel;
import javax.swing.JScrollPane;

import mainFrame.DrawPanel;
import model2D.Model2D;
import object2D.Object2D;

import org.json.JSONException;

import util.PixelPoint;


// ********************************************************************
// *** CLASS: DrawMapPanel
// ********************************************************************
public class DrawMapPanel extends DrawPanel implements Printable,Context.Constants
{ //private static final boolean DEBUG=true; // Overriding Context.Constants.DEBUG
  static final String TAG="mapEditor.DrawMapPanel";
  static final long serialVersionUID=0; // AD'HOC
  
  private static final double zoomFactor=1.2;

//  private Model2D objectModel;
//  public Model2D getObjectModel() { return(objectModel); }
  public String getName() {return((objectModel==null)?"UNKNOWN":objectModel.getName()); }

  private JScrollPane scrollPane;
//  private double currentScale=1;
//  public double getCurrentScale() { return(currentScale); }
  
  private boolean showMapImage=true;
  private boolean showObjects=true;
  private boolean showGrid=true;
	  
  public void setShowMapImage(boolean on) { showMapImage=on; repaint(); }
  public void showObjectsAction(boolean on) { showObjects=on; repaint(); }
  public void setShowGrid(boolean on) { showGrid=on; repaint(); }
  
  private Interactor mapInteractor;
  private Object2D.PointMark[] selectedPointMarks;
  
  public DrawMapPanel(Reader reader) throws IOException,JSONException
  { objectModel=new Model2D(this,reader); // Read JSON Document - Note: reader may be null
	requestResize();
	setInteractorAdapter(Interactor.MEASURE);
	setSelected();  
  }
  
  // ******************************************************************
  // *** METHOD: setInteractorAdapter
  // ******************************************************************
  public void setInteractorAdapter(int mouseMode)
  { Interactor a=null;
    switch(mouseMode)
    { case Interactor.MEASURE:        a=new MeasureInteractor(this);   break;
      case Interactor.EDIT:           a=new EditInteractor(this);      break; 
      case Interactor.DRAW_LINE:      a=new DrawLineInteractor(this);      break;
      case Interactor.DRAW_POLYGON:   a=new DrawPolygonInteractor(this);   break;
      case Interactor.DRAW_ELLIPSE:   a=new DrawEllipseInteractor(this);   break;
      case Interactor.DRAW_PARALLELOGRAM: a=new DrawParallelogramInteractor(this); break;
      case Interactor.DRAW_PATH:      a=new DrawPathInteractor(this);      break;
      case Interactor.DRAW_TEXT:      a=new DrawTextInteractor(this);      break;
    }
    setInteractorAdapter(a);
    MapEditor.getStatusLine().setMode(mapInteractor.getMouseModeMnemonic());
  }
  
  // ******************************************************************
  // *** METHOD: setInteractorAdapter
  // ******************************************************************
  private void setInteractorAdapter(Interactor newInteractor)
  { if(mapInteractor!=null)
    { this.removeKeyListener(mapInteractor);
	  this.removeMouseListener(mapInteractor);
	  this.removeMouseMotionListener(mapInteractor);
    }
    this.addKeyListener(newInteractor);
    this.addMouseListener(newInteractor);
    this.addMouseMotionListener(newInteractor);
    this.mapInteractor=newInteractor;  
  }
    
  // ******************************************************************
  // *** METHOD: getInteractorAdapter
  // ******************************************************************
  public Interactor getInteractorAdapter() { return(mapInteractor); }

  // ******************************************************************
  // *** METHOD: setSelected
  // ******************************************************************
  public void setSelected(Object2D selected)
  { selectedPointMarks=(selected==null)?null:selected.getPointMarks();
    ((MapTablePane)MapEditor.getSelectedTable()).setSelected(selected);
    repaint();
  }

  //*******************************************************************
  // *** METHOD: zoom
  //*******************************************************************
  public void zoom(boolean in)
  { currentScale=(in)?currentScale*zoomFactor:currentScale/zoomFactor;
    requestResize();
  }
  public void zoomReset() { currentScale=1; requestResize(); }
  
  // *************************************************************************
  // *** METHOD: writeJSONFile
  // *************************************************************************
  public void writeJSONFile(Writer writer) throws JSONException
  { objectModel.writeJSONFile(writer); }

  public void setScrollPane(JScrollPane scrollPane)
  {	if(DEBUG) Log.d(TAG,"setScrollPane: "+scrollPane);
	this.scrollPane=scrollPane;
  }
  
  public void requestResize()
  {	setPreferredSize(getScaledCanvasSize());
	if(scrollPane!=null) scrollPane.setViewportView(this);
  }
  private Dimension getScaledCanvasSize()
  {	int width=(int)(objectModel.getCanvasWidth()*currentScale);
    int height=(int)(objectModel.getCanvasHeight()*currentScale);
	if(DEBUG) Log.d(TAG,"getScaledCanvasSize: width="+width+", height="+height);
	return(new Dimension(width,height));
  }
  
//  public Object2D getObject(PixelPoint p)
//  { return(objectModel.getObject(p)); }
  
  public Object2D.PointMark getPointMark(PixelPoint p)
  { if(selectedPointMarks==null) return(null);
    if(selectedPointMarks.length==0) return(null);
    double x=p.getX();
    double y=p.getY();
	for(int i=0;i<selectedPointMarks.length;i++)
    { double xL=selectedPointMarks[i].getMapLocation().getX()-5;
      double xH=xL+10;//marks[i].getX()+5;
      double yL=selectedPointMarks[i].getMapLocation().getY()-5;
      double yH=yL+10;//marks[i].getY()+5;
//      boolean inXrange=( xL<=x ) && ( x<=xH);
//      if(DEBUG) Log.d(TAG,"Check PointMark "+i+": xL="+xL+", x="+x+" ,xH="+xH+", inXrange="+inXrange);
	  if( ( xL<=x ) && ( x<=xH) && ( yL<=y ) && ( y<=yH) ) return(selectedPointMarks[i]);
    }
	return(null);  
  }

  // *************************************************************************
  // *** METHOD: setSelected
  // *************************************************************************
  /**
  * Set this DrawPanel as selected among the tabed ones.
  **/
  public void setSelected()
  { int mouseMode=mapInteractor.getMouseMode();
    ((MapControlPanel)MapEditor.getControlPanel()).setMouseMode(mouseMode);
    String mouseModeMnemonic=mapInteractor.getMouseModeMnemonic();
    MapEditor.getStatusLine().setMode(mouseModeMnemonic);
  }

  // *************************************************************************
  // *** METHOD: paint
  // *************************************************************************
  public void paint(Graphics g)
  { super.paint(g); // Clear panel
    render((Graphics2D) g,currentScale);
    if(mapInteractor!=null) mapInteractor.paintMouseEffect((Graphics2D)g,this); 
	if(showGrid) objectModel.paintGrid((Graphics2D)g,this);
    if(selectedPointMarks!=null)
  	{ for(int i=0;i<selectedPointMarks.length;i++)
  	  selectedPointMarks[i].paint((Graphics2D)g);
  	}
  }

  // *************************************************************************
  // *** METHOD: render
  // *************************************************************************
  public void render(Graphics2D g,double scale)
  { if(scale!=1.0) g.transform(AffineTransform.getScaleInstance(scale,scale));
	if(showMapImage) objectModel.paintBackground((Graphics2D)g,this);
    if(showObjects) objectModel.paint((Graphics2D)g,this);
  }
  

  // *************************************************************************
  // *** METHOD: print
  // *************************************************************************
  public int print(Graphics g,PageFormat pageFormat,int pageIndex) throws PrinterException
  { render((Graphics2D) g,1.0);
	if(pageIndex==0) return(Printable.PAGE_EXISTS); 
	return(Printable.NO_SUCH_PAGE); 
  }

  public int getOrientation()
//  { return((getMapGrid().getCanvasWidth()>getMapGrid().getCanvasHeight())?PageFormat.LANDSCAPE:PageFormat.PORTRAIT);
  { return((getWidth()>getHeight())?PageFormat.LANDSCAPE:PageFormat.PORTRAIT);
  }

}
